package com.example.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.util.JWTUtil;
import com.example.lotterysystem.common.util.RegexUtil;
import com.example.lotterysystem.controller.param.LoginParam;
import com.example.lotterysystem.controller.param.MessageLoginParam;
import com.example.lotterysystem.controller.param.UserPasswordLoginParam;
import com.example.lotterysystem.controller.param.UserRegisterParam;
import com.example.lotterysystem.dao.dataObject.ActivityUserDO;
import com.example.lotterysystem.dao.dataObject.Encrypt;
import com.example.lotterysystem.dao.dataObject.UserDO;
import com.example.lotterysystem.dao.mapper.ActivityMapper;
import com.example.lotterysystem.dao.mapper.ActivityUserMapper;
import com.example.lotterysystem.dao.mapper.UserMapper;
import com.example.lotterysystem.service.UserService;
import com.example.lotterysystem.service.VerificationCodeService;
import com.example.lotterysystem.service.dto.UserDTO;
import com.example.lotterysystem.service.dto.UserLoginDTO;
import com.example.lotterysystem.service.dto.UserRegisterDTO;
import com.example.lotterysystem.service.enums.UserIdentityEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityUserMapper activityUserMapper;
    @Autowired
    private VerificationCodeService verificationCodeService;
    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //校验注册信息
        checkRegisterInfo(param);
        //加密私密数据过程(构造dao层请求)
        UserDO userDO = new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getMail());
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDO.setIdentity(param.getIdentity());
        if (StringUtils.hasText(param.getPassword())){
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }
        //保存数据
        userMapper.insert(userDO);
        //构造返回
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(LoginParam param) {
        UserLoginDTO userLoginDTO;
        if(param instanceof UserPasswordLoginParam loginParam){
            //密码登录流程
            userLoginDTO = loginByUserPassword(loginParam);
        } else if (param instanceof MessageLoginParam messageParam) {
            userLoginDTO = loginByMessage(messageParam);
        }else{
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }
        return userLoginDTO;
    }

    /**
     * 验证码登录
     *
     * @param messageParam
     * @return
     */
    private UserLoginDTO loginByMessage(MessageLoginParam messageParam) {
        if(!RegexUtil.checkMobile(messageParam.getLoginMobile())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //获取用户数据
        UserDO userDO = userMapper.getUserByPhoneNumber(new Encrypt(messageParam.getLoginMobile()));
        if(userDO==null){
            throw new ServiceException(ServiceErrorCodeConstants.User_INFO_NOT_EXIST);
        }else if(StringUtils.hasText(messageParam.getMandatoryIdentity())
            && !messageParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        String code = verificationCodeService.getVerificationCodeService(messageParam.getLoginMobile());
        if(!messageParam.getVerificationCode().equals(code)){
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_ERROR);
        }

        Map<String,Object> claim = new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDO userDO = null;
        //判断是手机还是邮箱
        if(RegexUtil.checkMobile(loginParam.getLoginName())){
            //电话登录
            userDO = userMapper.getUserByPhoneNumber(new Encrypt(loginParam.getLoginName()));
        }else if(RegexUtil.checkMail(loginParam.getLoginName())){
            //邮箱登录
            userDO = userMapper.getByMail(loginParam.getLoginName());
        }else{
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }

        if(null==userDO){
            throw new ServiceException(ServiceErrorCodeConstants.User_INFO_NOT_EXIST);
        }else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
                && !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        } else if (!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        Map<String,Object> claim = new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identityEnum) {
        String identityString =null==identityEnum?null: identityEnum.name();
        //查表
        List<UserDO> userDOS = userMapper.selectUserListByIdentity(identityString);
        List<UserDTO> userDTOList = userDOS.stream().map(userDO -> {
            UserDTO userDTO = new UserDTO();
            userDTO.setUserId(userDO.getId());
            userDTO.setUserName(userDO.getUserName());
            userDTO.setEmail(userDO.getEmail());
            userDTO.setEmail(userDO.getEmail());
            userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
            return userDTO;
        }).toList();
        return userDTOList;
    }

    @Override
    public Boolean deleteUser(Long userId) {
        Boolean result = checkUser(userId);
        if (!result){
            logger.error("删除失败!活动或用户正在进行抽奖!");
            throw new ServiceException(ServiceErrorCodeConstants.DELETE_USER_FALSE);
        }
        userMapper.deleteUser(userId);
        return true;
    }

    private Boolean checkUser(Long userId) {
        //和删除奖品的步骤大致上相同的
        if (null==userId){
            logger.warn("传递的userId为空!");
            throw new ServiceException(ServiceErrorCodeConstants.USERID_IS_EMPTY);
        }
        //判断user是否存在
        UserDO userDO = userMapper.selectById(userId);
        if(null==userDO){
            logger.error("选择的人员不存在! userId:{}",userId);
            throw new ServiceException(ServiceErrorCodeConstants.USERID_IS_NOT_EXIST);
        }
        List<ActivityUserDO> activityUserDOS = activityUserMapper.selectByUserId(userId);
        int userInit = activityUserMapper.countUserInit(userId,"INIT");
        int activityInit = 0;
        if(!CollectionUtils.isEmpty(activityUserDOS)){
            activityInit = activityMapper.countActivityInitByUser(activityUserDOS,"INIT");
        }
        if(userInit!=0||activityInit!=0){
            return false;
        }
        return true;
    }


    private void checkRegisterInfo(UserRegisterParam param) {
        if(null==param){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_EMPTY);
        }
        //校验使用正则表达式
        //校验邮箱格式 xxx@xxx.xxx
        if(!RegexUtil.checkMail(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //校验手机号格式
        if(!RegexUtil.checkMobile(param.getPhoneNumber())){
            throw  new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //校验身份信息
        if(null==UserIdentityEnum.forName(param.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //校验管理员密码必填
        if(param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())//name用来返回枚举类常量的名称
        && !StringUtils.hasText(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
        //密码格式校验 大于等于6位
        if(StringUtils.hasText(param.getPassword())
                &&!RegexUtil.checkPassword(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //手机号邮箱唯一
        if(checkMailUsed(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }
        if(checkPhoneNumber(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    public boolean checkMailUsed(String mail){
        int count = userMapper.countByMail(mail);
        return count>0;
    }
    public boolean checkPhoneNumber(String number){
        int count = userMapper.countByPhone(new Encrypt(number));
        return count>0;
    }
}
